package com.zz.chenko.shiro;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zz.chenko.common.utils.CacheUtil;
import com.zz.chenko.common.utils.CollectionUtil;
import com.zz.chenko.common.utils.Constant;
import com.zz.chenko.common.utils.EncryptUtil;
import com.zz.chenko.sys.entity.User;
import com.zz.chenko.sys.service.UserService;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Collection;

public class MyRealm extends AuthorizingRealm {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private UserService userService;

    /**
     * 认证回调函数, 登录时调用.
     */
    @SuppressWarnings("unchecked")
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        String loginName = (String) token.getPrincipal();
        logger.info("loginName: {0}", loginName);
        EntityWrapper<User> wrapper = new EntityWrapper<>();
        wrapper.addFilter("login_name = {0}", loginName);
        User user = userService.selectOne(wrapper);
        if (user != null) {
            if (Constant.LOCKED.equals(user.getLockFlag())) {
                throw new LockedAccountException("该用户已经被锁定不能登录，请与管理员联系！");
            }
            if (Constant.DELETED.equals(user.getDelFlag())) {
                throw new DisabledAccountException("该用户已被禁用！");
            }
            String salt = EncryptUtil.base64Decode(StringUtils.substring(user.getLoginPassword(), 0, 16));
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(loginName,
                    StringUtils.substring(user.getLoginPassword(), 16), ByteSource.Util.bytes(salt), getName());

            // 当验证都通过后，把用户信息放在session里
            Session session = SecurityUtils.getSubject().getSession();
            session.setAttribute("user", user);
            session.setAttribute("userId", user.getId());

            return info;
        } else {
            throw new AuthenticationException("用户名或密码不正确！");
        }
    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String loginName = SecurityUtils.getSubject().getPrincipal().toString();
        // 权限信息对象info,用来存放查出的用户的所有的角色（role）及权限（permission）
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        if (loginName != null) {
            // 将角色加入到shiro管理中
            info.addRoles(CollectionUtil.extractToList((Collection) CacheUtil.get("role", "roleList"), "roleName"));
            // 将权限加入到shiro管理中
            info.addStringPermissions(CollectionUtil
                    .extractToList((Collection) CacheUtil.get("permission", "permissionList"), "permissionName"));
        }
        return info;
    }

    /**
     * 更新用户授权信息缓存.
     */
    public void clearCachedAuthorizationInfo(String principal) {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
        clearCachedAuthorizationInfo(principals);
    }

    /**
     * 清除所有用户授权信息缓存.
     */
    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }
}
